#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <queue>
#include <functional>
using namespace std;

template<class T>
class ThreadPool
{
    #define DEFAULT_SIZE 5
    using func_t = function<void(const T&)>;
public:
    ThreadPool(func_t func, size_t size = DEFAULT_SIZE):_size(size), _func(func)
    {}
    ~ThreadPool()
    {
        for(int i = 0; i < _size; i++)
        {
            _threads[i].join();
        }
    }
    void Init()
    {}
    void Start()
    {
        for(int i = 0; i < _size; i++)
        {
            _threads.push_back(thread(Routine, this));
        }
    }

    static void Routine(ThreadPool<T>* ptr)
    {
        while(true)
        {
            T tmp;
            {
                unique_lock<mutex> lck(ptr->_mutex);
                while(ptr->_task.size() == 0)
                {
                    ptr->_cond.wait(lck);
                } 
                tmp = ptr->_task.front(); ptr->_task.pop();
            }
            ptr->_func(tmp);
        }
    }

    void PushTask(const T& task)
    {
        unique_lock<mutex> lck(_mutex);
        _task.push(task);
        _cond.notify_one();
    }
private:
    queue<T> _task;
    mutex _mutex;
    condition_variable _cond;
    vector<thread> _threads;
    size_t _size;
    func_t _func;
};